import { _decorator, Component, Node, Enum, EventTouch, UITransformComponent, Vec3, view, find, UITransform, Input, Touch, Scene, director, geometry, PhysicsSystem, input, Vec2, KeyCode, EventKeyboard } from "cc";
import { Constant, Group } from "../Common/Constant";
import { ZTool } from "../Common/ZTool";
import { EasyController, EasyControllerEvent } from "../Controller/EasyController";
import { GameManager } from "../Manager/GameManager";
const { ccclass, property } = _decorator;

@ccclass("Joystick")
export class Joystick extends Component {

    private _cameraArea: UITransform = null;
    private _joystickBase: UITransform = null;

    private _joystickDot: Node = null;

    private _scene: Scene = null;

    private static canRaycast = true;

    private _movementTouch: Touch = null;
    private _cameraTouchA: Touch = null;
    private _cameraTouchB: Touch = null;

    private _distanceOfTwoTouchPoint: number = 0;
    private _cameraSensitivity: number = 0.1;

    start() {
        let joystickArea = this.node.getChildByName(`JoystickArea`).getComponent(UITransform);
        joystickArea.node.on(Input.EventType.TOUCH_START, this.OnTouchStart_JoystickArea, this);
        joystickArea.node.on(Input.EventType.TOUCH_MOVE, this.OnTouchMove_JoystickArea, this);
        joystickArea.node.on(Input.EventType.TOUCH_END, this.OnTouchEnd_JoystickArea, this);
        joystickArea.node.on(Input.EventType.TOUCH_CANCEL, this.OnTouchEnd_JoystickArea, this);

        this._cameraArea = this.node.getChildByName('CameraArea').getComponent(UITransform);
        this._cameraArea.node.on(Input.EventType.TOUCH_START, this.OnTouchStart_CameraArea, this);
        this._cameraArea.node.on(Input.EventType.TOUCH_MOVE, this.OnTouchMove_CameraArea, this);
        this._cameraArea.node.on(Input.EventType.TOUCH_END, this.OnTouchEnd_CameraArea, this);
        this._cameraArea.node.on(Input.EventType.TOUCH_CANCEL, this.OnTouchEnd_CameraArea, this);

        input.on(Input.EventType.KEY_DOWN, this.onKeyDown, this);
        input.on(Input.EventType.KEY_UP, this.onKeyUp, this);

        this._joystickBase = this.node.getChildByName('JoystickBase').getComponent(UITransform);
        this._joystickDot = this._joystickBase.node.getChildByName('JoystickDot');

        this._scene = director.getScene();
    }

    OnTouchStart_JoystickArea(event: EventTouch) {
        let touches = event.getTouches();
        for (let i = 0; i < touches.length; ++i) {
            let touch = touches[i];
            let x = touch.getUILocationX();
            let y = touch.getUILocationY();
            if (!this._movementTouch) {
                //we sub halfWidth,halfHeight here.
                //because, the touch event use left bottom as zero point(0,0), ui node use the center of screen as zero point(0,0)
                //this._ctrlRoot.setPosition(x - halfWidth, y - halfHeight, 0);

                let halfWidth = this._cameraArea.width / 2;
                let halfHeight = this._cameraArea.height / 2;

                this._joystickBase.node.active = true;
                this._joystickBase.node.setPosition(x - halfWidth, y - halfHeight, 0);
                this._joystickDot.setPosition(0, 0, 0);
                this._movementTouch = touch;
            }
        }
    }

    OnTouchMove_JoystickArea(event: EventTouch) {
        let touches = event.getTouches();
        for (let i = 0; i < touches.length; ++i) {
            let touch = touches[i];
            if (this._movementTouch && touch.getID() == this._movementTouch.getID()) {
                let halfWidth = this._cameraArea.width / 2;
                let halfHeight = this._cameraArea.height / 2;
                let x = touch.getUILocationX();
                let y = touch.getUILocationY();

                let pos = this._joystickBase.node.position;
                let ox = x - halfWidth - pos.x;
                let oy = y - halfHeight - pos.y;

                let len = Math.sqrt(ox * ox + oy * oy);
                if (len <= 0) {
                    return;
                }

                let dirX = ox / len;
                let dirY = oy / len;
                let radius = this._joystickBase.width / 2;
                if (len > radius) {
                    len = radius;
                    ox = dirX * radius;
                    oy = dirY * radius;
                }

                this._joystickDot.setPosition(ox, oy, 0);

                // // degree 0 ~ 360 based on x axis.
                // let degree = Math.atan(dirY / dirX) / Math.PI * 180;
                // if (dirX < 0) {
                //     degree += 180;
                // }
                // else {
                //     degree += 360;
                // }

                this._scene.emit(EasyControllerEvent.MOVEMENT, dirX, dirY, len / radius);
            }
        }
    }

    OnTouchEnd_JoystickArea(event: EventTouch) {
        let touches = event.getTouches();
        for (let i = 0; i < touches.length; ++i) {
            let touch = touches[i];
            if (this._movementTouch && touch.getID() == this._movementTouch.getID()) {
                this._scene.emit(EasyControllerEvent.MOVEMENT_STOP);
                this._movementTouch = null;
                this._joystickBase.node.active = false;
            }
        }
    }

    OnTouchStart_CameraArea(event: EventTouch) {
        let touches = event.getAllTouches();
        this._cameraTouchA = null;
        this._cameraTouchB = null;

        if (Joystick.canRaycast) {
            const ray = new geometry.Ray();
            const loaction = event.getLocation();

            GameManager.Instance.playerCamera.screenPointToRay(loaction.x, loaction.y, ray);

            if (PhysicsSystem.instance.raycastClosest(ray, 0xffffffff, 2)) {
                const result = PhysicsSystem.instance.raycastClosestResult;

                switch (result.collider.getGroup()) {
                    case Group.Props:

                        break;
                }

                console.log("射线击中：" + result.collider.node.name);
            }
        }

        for (let i = touches.length - 1; i >= 0; i--) {
            let touch = touches[i];
            if (this._movementTouch && touch.getID() == this._movementTouch.getID()) {
                continue;
            }
            if (this._cameraTouchA == null) {
                this._cameraTouchA = touches[i];
            }
            else if (this._cameraTouchB == null) {
                this._cameraTouchB = touches[i];
                break;
            }
        }

    }

    OnTouchMove_CameraArea(event: EventTouch) {
        let touches = event.getTouches();
        for (let i = 0; i < touches.length; ++i) {
            let touch = touches[i];
            let touchID = touch.getID();
            //two touches, do camera zoom.
            if (this._cameraTouchA && this._cameraTouchB) {
                console.log(touchID, this._cameraTouchA.getID(), this._cameraTouchB.getID());
                let needZoom = false;
                if (touchID == this._cameraTouchA.getID()) {
                    this._cameraTouchA = touch;
                    needZoom = true;
                }
                if (touchID == this._cameraTouchB.getID()) {
                    this._cameraTouchB = touch;
                    needZoom = true;
                }

                if (needZoom) {
                    let newDist = this.GetDistOfTwoTouchPoints();
                    let delta = this._distanceOfTwoTouchPoint - newDist;
                    this._scene.emit(EasyControllerEvent.CAMERA_ZOOM, delta);
                    this._distanceOfTwoTouchPoint = newDist;
                }
            }
            //only one touch, do camera rotate.
            else if (this._cameraTouchA && touchID == this._cameraTouchA.getID()) {
                let dt = touch.getDelta();
                let rx = dt.y * this._cameraSensitivity;
                let ry = -dt.x * this._cameraSensitivity;
                this._scene.emit(EasyControllerEvent.CAMERA_ROTATE, rx, ry);
            }
        }
    }

    OnTouchEnd_CameraArea(event: EventTouch) {
        let touches = event.getAllTouches();
        let hasTouchA = false;
        let hasTouchB = false;
        for (let i = 0; i < touches.length; ++i) {
            let touch = touches[i];
            let touchID = touch.getID();
            if (this._cameraTouchA && touchID == this._cameraTouchA.getID()) {
                hasTouchA = true;
            }
            else if (this._cameraTouchB && touchID == this._cameraTouchB.getID()) {
                hasTouchB = true;
            }
        }

        if (!hasTouchA) {
            this._cameraTouchA = null;
        }
        if (!hasTouchB) {
            this._cameraTouchB = null;
        }
    }

    private GetDistOfTwoTouchPoints(): number {
        let touchA = this._cameraTouchA;
        let touchB = this._cameraTouchB;
        if (!touchA || !touchB) {
            return 0;
        }
        let dx = touchA.getLocationX() - touchB.getLocationX();
        let dy = touchB.getLocationY() - touchB.getLocationY();
        return Math.sqrt(dx * dx + dy * dy);
    }

    update(deltaTime: number) {
    }

    private _keys = [];
    private _degree: number = 0;
    dir: Vec2 = new Vec2(0, 0);

    onKeyDown(event: EventKeyboard) {
        let keyCode = event.keyCode;
        if (keyCode == KeyCode.KEY_A || keyCode == KeyCode.KEY_S || keyCode == KeyCode.KEY_D || keyCode == KeyCode.KEY_W) {
            if (this._keys.indexOf(keyCode) == -1) {
                this._keys.push(keyCode);
                switch (keyCode) {
                    case KeyCode.KEY_A:
                        {
                            this.dir.x = -1;
                        }
                        break;
                    case KeyCode.KEY_D:
                        {
                            this.dir.x = 1;
                        }
                        break;
                    case KeyCode.KEY_W:
                        {
                            this.dir.y = 1;
                        }
                        break;
                    case KeyCode.KEY_S:
                        {
                            this.dir.y = -1;
                        }
                        break;
                }
                this.updateDirection();
            }
        }

        //         if(keyCode == KeyCode.SPACE){
        //              this._scene.emit(EasyControllerEvent.JUMP);
        //          }
    }

    onKeyUp(event: EventKeyboard) {
        let keyCode = event.keyCode;
        if (keyCode == KeyCode.KEY_A || keyCode == KeyCode.KEY_S || keyCode == KeyCode.KEY_D || keyCode == KeyCode.KEY_W) {
            let index = this._keys.indexOf(keyCode);
            if (index != -1) {
                this._keys.splice(index, 1);
                switch (keyCode) {
                    case KeyCode.KEY_A:
                    case KeyCode.KEY_D:
                        {
                            this.dir.x = 0;
                        }
                        break;
                    case KeyCode.KEY_W:
                    case KeyCode.KEY_S:
                        {
                            this.dir.y = 0;
                        }
                        break;
                }
                this.updateDirection();
            }
        }
    }

    private key2dirMap = null;

    updateDirection() {
        if (this.key2dirMap == null) {
            this.key2dirMap = {};
            this.key2dirMap[0] = -1;
            this.key2dirMap[KeyCode.KEY_A] = new Vec2(-1, 0);//180
            this.key2dirMap[KeyCode.KEY_D] = new Vec2(1, 0);//0
            this.key2dirMap[KeyCode.KEY_W] = new Vec2(0, 1);//90
            this.key2dirMap[KeyCode.KEY_S] = new Vec2(0, -1);//270

            this.key2dirMap[KeyCode.KEY_A * 1000 + KeyCode.KEY_W] = this.key2dirMap[KeyCode.KEY_W * 1000 + KeyCode.KEY_A] = new Vec2(-1, 1);//135
            this.key2dirMap[KeyCode.KEY_D * 1000 + KeyCode.KEY_W] = this.key2dirMap[KeyCode.KEY_W * 1000 + KeyCode.KEY_D] = new Vec2(1, 1);//45
            this.key2dirMap[KeyCode.KEY_A * 1000 + KeyCode.KEY_S] = this.key2dirMap[KeyCode.KEY_S * 1000 + KeyCode.KEY_A] = new Vec2(-1, -1);//225
            this.key2dirMap[KeyCode.KEY_D * 1000 + KeyCode.KEY_S] = this.key2dirMap[KeyCode.KEY_S * 1000 + KeyCode.KEY_D] = new Vec2(1, -1);//315

            this.key2dirMap[KeyCode.KEY_A * 1000 + KeyCode.KEY_D] = this.key2dirMap[KeyCode.KEY_D];
            this.key2dirMap[KeyCode.KEY_D * 1000 + KeyCode.KEY_A] = this.key2dirMap[KeyCode.KEY_A];
            this.key2dirMap[KeyCode.KEY_W * 1000 + KeyCode.KEY_S] = this.key2dirMap[KeyCode.KEY_S];
            this.key2dirMap[KeyCode.KEY_S * 1000 + KeyCode.KEY_W] = this.key2dirMap[KeyCode.KEY_W];
        }
        let keyCode0 = this._keys[this._keys.length - 1] || 0;
        let keyCode1 = this._keys[this._keys.length - 2] || 0;
        this._degree = this.key2dirMap[keyCode1 * 1000 + keyCode0];
        if (this._degree == null || this._degree < 0) {
            this._scene.emit(EasyControllerEvent.MOVEMENT_STOP);
        }
        else {
            this._scene.emit(EasyControllerEvent.MOVEMENT, this.dir.x, this.dir.y, 1.0);
        }
    }

}